package main

import (
	"context"
	"fmt"
	"net/rpc"
	"time"

	"gitee.com/go-course/go11/skill/rpc/hello/model"
)

// func main() {
// 	// 1. 建立网络链接
// 	// 首先是通过rpc.Dial拨号RPC服务, 建立连接
// 	client, err := rpc.Dial("tcp", "localhost:1234")
// 	if err != nil {
// 		log.Fatal("dialing:", err)
// 	}

// 	// 2. 通过网络链接，调用Server的服务(RPC)
// 	// (i *HelloWorldServiceImpl) Hello(in *HelloRequest, out *HelloResponse)

// 	// 然后通过client.Call调用具体的RPC方法
// 	// 在调用client.Call时:
// 	// 		第一个参数是用点号链接的RPC服务名字和方法名字，
// 	// 		第二个参数是 请求参数
// 	//      第三个是请求响应, 必须是一个指针, 有底层rpc服务帮你赋值
// 	// 能不能封装一个SDK(RPC), 来简化用户的使用
// 	// client = new client
// 	// resp, err = client.Hello(ctx, request)
// 	//
// 	resp := &model.HelloResponse{}
// 	err = client.Call("HelloService.Hello", &model.HelloRequest{
// 		Name: "alice",
// 	}, resp)
// 	if err != nil {
// 		log.Fatal(err)
// 	}

// 	fmt.Println(resp)
// }

// NewRestfulClient
func NewRpcClient(address string) (model.Service, error) {
	// 1. 建立网络链接
	// 首先是通过rpc.Dial拨号RPC服务, 建立连接
	client, err := rpc.Dial("tcp", address)
	if err != nil {
		return nil, err
	}

	return &Client{
		rpc:           client,
		serverAddress: address,
	}, nil
}

// 不想面向接口编程 你也可以不用
var _ model.Service = &Client{}

type Client struct {
	rpc           *rpc.Client
	serverAddress string
}

// 业务参数(用户传递的参数):  in *model.HelloRequest
// 非业务参数: 比如 用户的请求里面代理一个User身份信息， TOKEN --> 中间件处理后(UserObj),请求处理产生的一些中间数据
// 把它叫做 请求的上下文(context) ,后续处理的请求就可以从context中获取这些中间信息 ctx.GetUserObj()
// 还能实现Cancel 请求的取消
func (c *Client) Hello(ctx context.Context, in *model.HelloRequest) (
	*model.HelloResponse, error) {
	resp := &model.HelloResponse{}
	err := c.rpc.Call("HelloService.Hello", in, resp)
	if err != nil {
		return nil, err
	}
	return resp, nil
}

func main() {
	// 1. 建立网络链接
	// 首先是通过rpc.Dial拨号RPC服务, 建立连接
	client, err := NewRpcClient("localhost:1234")
	if err != nil {
		panic(err)
	}

	// 能不能封装一个SDK(RPC), 来简化用户的使用
	// client = new client
	// resp, err = client.Hello(ctx, request)
	// 先定义一个client对象
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
	go func() {
		// 到3秒的时候用户取消了
		time.Sleep(3 * time.Second)
		cancel()
	}()
	resp, err := client.Hello(
		ctx,
		&model.HelloRequest{Name: "alice"},
	)
	if err != nil {
		panic(err)
	}

	fmt.Println(resp)
}
